package xml.form;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import xml.validator.Validator;
import org.restlet.representation.Representation;

/**
 * Classe de formulaire basé sur la classe de formulaire de restlet qui ajoute la possibilité de
 * valider les paramètres
 */
public class Form extends org.restlet.data.Form {

    private List<String> messages;
    private Map<String, List<Validator<String>>> validatorsPerParamaterName;

    public Form() {
        super();

        this.validatorsPerParamaterName = new HashMap<String, List<Validator<String>>>();
    }

    public Form(Representation entity) {
        super(entity);

        this.validatorsPerParamaterName = new HashMap<String, List<Validator<String>>>();
    }

    /**
     * Ajoute un validator pour le parametre donné
     *
     * @require parameterName != null
     *
     * @param parameterName
     * @param validator
     * @throws NullPointerException
     * @throws UnsupportedOperationException
     */
    public void addValidator(String parameterName, Validator<String> validator) {
        assert parameterName != null;


        if (!validatorsPerParamaterName.containsKey(parameterName)) {
            validatorsPerParamaterName.put(parameterName, new ArrayList<Validator<String>>());
        }

        validatorsPerParamaterName.get(parameterName).add(validator);

    }

    /**
     * Ajoute les validator passés en paramètre au paramètre donné
     *
     * @require parameterName != null;
     *
     * @param parameterName
     * @param validators
     */
    public void addValidators(String parameterName, Validator<String>... validators) {
        assert parameterName != null;

        for (Validator<String> validator : validators) {
            addValidator(parameterName, validator);
        }
    }

    /**
     * Enlève tous les validator pour le parameterName
     *
     * @require parameterName != null
     *
     * @param parameterName
     */
    public void clearValidators(String parameterName) {
        assert parameterName != null;

        if (this.validatorsPerParamaterName.containsKey(parameterName)) {
            this.validatorsPerParamaterName.get(parameterName).clear();
        }
    }

    public void setValidators(String parameterName, List<Validator<String>> validators) {
        assert parameterName != null;

        this.validatorsPerParamaterName.put(parameterName, validators);

    }

    /**
     * Retourne une liste non modifiable des validators pour ce champs
     *
     * @require parameterName != null
     *
     * @param parameterName
     * @return
     */
    public List<Validator<String>> getValidators(String parameterName) {
        assert parameterName != null;

        List<Validator<String>> validators;

        if (this.validatorsPerParamaterName.containsKey(parameterName)) {
            validators = this.validatorsPerParamaterName.get(parameterName);
        } else {
            validators = Collections.emptyList();
        }

        return validators;
    }

    /**
     * Retourne la liste des messages d'erreur ou une liste vide si il n'y a
     * pas de messages
     *
     * @return
     */
    public List<String> getMessages() {
        List<String> msg;
        if (messages != null) {
            msg = Collections.unmodifiableList(messages);
        } else {
            msg = Collections.emptyList();
        }

        return msg;
    }

    private void addMessages(List<String> msgs) {
        if (messages == null) {
            messages = new ArrayList<String>();
        }
        messages.addAll(msgs);
    }

    private void clearMessages() {
        if (messages != null) {
            messages.clear();
        }
    }

    /**
     * Méthode qui, pour chaque paramètre contenu dans ce formulaire, teste sa validité
     * Si le paramètre n'est pas valide alors la liste des messages d'erreurs concernant
     * sa non validité est rajouté à la liste des messages d'erreurs
     * de ce formulaire
     * @return true si le formulaire est valide, false sinon
     */
    public boolean isValid() {
        boolean result = true;
        this.clearMessages();
        for (String parameterName : this.validatorsPerParamaterName.keySet()) {
            for (Validator<String> validator : this.validatorsPerParamaterName.get(parameterName)) {
                result = result && validator.isValid(this.getFirstValue(parameterName));
                addMessages(validator.getMessages());
                validator.clearMessages();
            }
        }
        return result;
    }
}
